import { noop } from 'lodash';
import { mountRootParcel, registerApplication, start as startSingleSpa } from 'single-spa';
import { FrameworkConfiguration, FrameworkLifeCycles, LoadableApp, MicroApp, RegistrableApp } from './interfaces';
import { loadApp } from './loader';
import { doPrefetchStrategy } from './prefetch';
import { Deferred, toArray } from './utils';


// 存放所有的微应用
let microApps = [];


export let frameworkConfiguration = {};
const frameworkStartedDefer = new Deferred();

/**
 * 注册微应用，基于路由配置
 * @param apps = [
 *  {
 *    name: 'react16',
 *    entry: '//localhost:7100',
 *    container: '#subapp-viewport',
 *    loader,
 *    activeRule: '/react16'
 *  },
 *  ...
 * ]
 * @param lifeCycles = { ...各个生命周期方法对象 }
 */
export function registerMicroApps(apps, lifeCycles) {

  // 防止微应用重复注册，得到所有没有被注册的微应用列表
  const unregisteredApps = apps.filter(app => !microApps.some(registeredApp => registeredApp.name === app.name));

  // 所有的微应用 = 已注册 + 未注册的(将要被注册的)
  microApps = [...microApps, ...unregisteredApps];

  // 注册每一个微应用
  unregisteredApps.forEach(app => {
     // 注册时提供的微应用基本信息
    const {
      name, 
      activeRule,
      loader = noop, //用于返回“undefined”
      props,
      ...appConfig
    } = app;
    // 调用 single-spa 的 registerApplication 方法注册微应用
    registerApplication({
      name, // 微应用名称
      // 微应用的加载方法，Promise<生命周期方法组成的对象>
      app: async () => {
        loader(true); // 加载微应用时主应用显示 loading 状态
        await frameworkStartedDefer.promise;
        const {
          mount,
          ...otherMicroAppConfigs
        } = await loadApp({
          name,
          props,
          ...appConfig
        }, frameworkConfiguration, lifeCycles);
        return {
          mount: [async () => loader(true), ...toArray(mount), async () => loader(false)],
          ...otherMicroAppConfigs
        };
      },
      activeWhen: activeRule,
      customProps: props
    });
  });
}

export function loadMicroApp(app, configuration, lifeCycles) {
  const {
    props
  } = app;
  return mountRootParcel(() => loadApp(app, configuration ?? frameworkConfiguration, lifeCycles), {
    domElement: document.createElement('div'),
    ...props
  });
}


export function start(opts = {}) {
  frameworkConfiguration = {
    prefetch: true,
    singular: true,
    sandbox: true,
    ...opts
  };
  const {
    prefetch,
    sandbox,
    singular,
    urlRerouteOnly,
    ...importEntryOpts
  } = frameworkConfiguration;

  if (prefetch) {
    doPrefetchStrategy(microApps, prefetch, importEntryOpts);
  }

  if (sandbox) {
    if (!window.Proxy) {
      console.warn('[qiankun] Miss window.Proxy, proxySandbox will degenerate into snapshotSandbox');

      if (!singular) {
        console.error('[qiankun] singular is forced to be true when sandbox enable but proxySandbox unavailable');
        frameworkConfiguration.singular = true;
      }
    }
  }

  startSingleSpa({
    urlRerouteOnly
  });
  frameworkStartedDefer.resolve();
}